////////////////////////////////////////////////////////
//
//  Copyright(C), 2005-2022, GEC Tech. Co., Ltd.
//  www.yueqian.com.cn  ALL RIGHT RESERVED
//
//  文件: nonBlockUDP.c
//  描述: 基于UDP协议的非阻塞轮询方式，接收对端数据
//
///////////////////////////////////////////////////////

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>

#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>

#define PORT 50021

int main(int argc, char const *argv[])
{
    // 创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sockfd == -1)
    {
        perror("创建套接字失败");
        exit(0);
    }

    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务器IP
    addr.sin_port = htons(PORT); // 接收数据端口

    // 绑定上述地址
    if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
        perror("绑定地址失败");

    struct sockaddr_in clientAddr;
    char buf[100];

    // 将套接字设定位非阻塞
    long state = fcntl(sockfd, F_GETFL);
    state |= O_NONBLOCK;
    fcntl(sockfd, F_SETFL, state);

    // 轮询接收UDP数据
    for(int i; ; i++, i%=26)
    {
        bzero(buf, 100);

        socklen_t len = sizeof(clientAddr);
        bzero(&clientAddr, len);

        // 等待UDP数据
        int n = recvfrom(sockfd, buf, 100, 0,
                                (struct sockaddr *)&clientAddr, &len);

        // 资源暂时不可得
        if(n == -1 && errno == EAGAIN)
        {
            fprintf(stderr, "%c", 'a'+i);
            usleep(1000);
            continue;
        }

        // 遇到真正的错误
        else if(n == -1)
        {
            perror("recvfrom()失败");
            break;
        }

        // 正常读到数据
        else if(n > 0)
        {
            printf("[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
                                    ntohs(clientAddr.sin_port), buf);
        }
    }

    close(sockfd);
    return 0;
}
